package br.com.advance.automacao.services.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import se.opendataexchange.ethernetip4j.clx.ControlLogixConnector;
import se.opendataexchange.ethernetip4j.clx.UnconnectedMessagingRead;
import se.opendataexchange.ethernetip4j.exceptions.NotImplementedException;
import br.com.advance.automacao.enumeration.TipoErro;
import br.com.advance.automacao.model.CLP;
import br.com.advance.automacao.model.Erro;
import br.com.advance.automacao.model.Evento;
import br.com.advance.automacao.model.MTBF;
import br.com.advance.automacao.model.Turno;
import br.com.advance.automacao.services.ErroService;
import br.com.advance.automacao.services.EthernetIp4JService;
import br.com.advance.automacao.services.RegistroErroSistemaService;
import br.com.advance.automacao.services.dto.EficienciaCLP;

public class EthernetIp4JServiceImpl implements EthernetIp4JService {

	private static final Logger logger = Logger
			.getLogger(EthernetIp4JServiceImpl.class);


	@Autowired
	private ErroService erroService;

	@Autowired
	private RegistroErroSistemaService registroErroSistemaService;

	@Override
	public EficienciaCLP obterEficienciaCLP(CLP clp) {
		ControlLogixConnector comm = null;
		EficienciaCLP eficiencia = null;
		try {
			comm = new ControlLogixConnector(
					clp.getIp(), 0xAF12);
			Integer gef = (Integer) obterDadosCLP("G_Machine_Efficiency", 1, comm);
			comm.disconnect();
			comm = new ControlLogixConnector(
					clp.getIp(), 0xAF12);
			Integer display = (Integer) obterDadosCLP("Display", 1, comm);
			comm.disconnect();
			comm = new ControlLogixConnector(
					clp.getIp(), 0xAF12);
			Integer rpm = (Integer) obterDadosCLP("RPM", 1, comm);
			comm.disconnect();
			comm = new ControlLogixConnector(
					clp.getIp(), 0xAF12);
			Integer mtbf = (Integer) obterDadosCLP("MTBFAtual", 1, comm);
			eficiencia = new EficienciaCLP(clp.getNome(), gef, display, rpm, mtbf);
		} catch (IOException e) {
			logger.error(
					"Erro ao tentar obter dados de eficiencia de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
		} catch (NotImplementedException e) {
			logger.error(
					"Erro ao tentar obter dados de eficiencia de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
		} catch (InterruptedException e) {
			logger.error(
					"Erro ao tentar obter dados de eficiencia de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
		} catch (Exception e) {
			logger.error(
					"Erro ao tentar obter dados de eficiencia de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);	
		}
		if(comm != null) {
			try {
				comm.disconnect();
				comm = null;
			} catch (Exception e) {
				logger.error(
						"Erro ao tentar obter dados de eficiencia de turno do CLP ID: "
								+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
								+ clp.getNome(), e);	
			}
		}
		return eficiencia;
	}

	@Override
	public Object[] buscarEventosFimTurno(CLP clp, Date data, Turno turno) {
		Object[] retorno = new Object[2];
		List<Evento> eventos = new ArrayList<Evento>();
		ControlLogixConnector comm = null;
		try {
			comm = new ControlLogixConnector(
					clp.getIp(), 0xAF12);
			Integer[] codigos = (Integer[]) obterDadosCLP("EventoCodigo", 400, comm);
			Integer[] quantidades = (Integer[]) obterDadosCLP("EventoTempo", 400, comm);
			for(int i = 0; i < 400; i++) {
				Integer codigo = codigos[i];
				if(codigo == 0) {
					break;
				}
				Evento evento = new Evento();
				evento.setClp(clp);
				evento.setData(data);
				evento.setHora(data);
				evento.setDataHora(data);
				Erro erro = erroService.buscarErroPorCodigoClp(clp.getId(), String.valueOf(codigo));
				if(erro == null) {
					logger.error(
							"Erro codigo: " + codigo + "nao encontrado para o CLP: "
									+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
									+ clp.getNome());
					registroErroSistemaService.criar(TipoErro.ERROS_EQUIPAMENTOS, "Código desconhecido encontrado: " + codigo + " | CLP id: " + clp.getId());
					continue;
				}
				evento.setErro(erro);
				evento.setTempo(quantidades[i]);
				evento.setTurno(turno);
				eventos.add(evento);

			}
			retorno[0] = eventos;
			Integer valorMtbf = (Integer) obterDadosCLP("MTBF", 1, comm);
			MTBF mtbf = new MTBF();
			mtbf.setClp(clp);
			mtbf.setData(data);
			mtbf.setHora(data);
			mtbf.setDataHora(data);
			mtbf.setTurno(turno);
			mtbf.setValor(new BigDecimal(valorMtbf.toString()).divide(new BigDecimal("100")).doubleValue());
			retorno[1] = mtbf;
		} catch (IOException e) {
			logger.error(
					"Erro ao tentar obter dados de fim de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
			registroErroSistemaService.criar(TipoErro.ERROS_EQUIPAMENTOS, "Erro ao tentar obter dados de fim de turno do CLP ID: "
					+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
					+ clp.getNome() + " Stack: " + e.getMessage());
		} catch (NotImplementedException e) {
			logger.error(
					"Erro ao tentar obter dados de fim de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
			registroErroSistemaService.criar(TipoErro.ERROS_EQUIPAMENTOS, "Erro ao tentar obter dados de fim de turno do CLP ID: "
					+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
					+ clp.getNome() + " Stack: " + e.getMessage());
		} catch (InterruptedException e) {
			logger.error(
					"Erro ao tentar obter dados de fim de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
			registroErroSistemaService.criar(TipoErro.ERROS_EQUIPAMENTOS, "Erro ao tentar obter dados de fim de turno do CLP ID: "
					+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
					+ clp.getNome() + " Stack: " + e.getMessage());
		} catch(Exception e ) {
			logger.error(
					"Erro ao tentar obter dados de fim de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
			registroErroSistemaService.criar(TipoErro.ERROS_EQUIPAMENTOS, "Erro ao tentar obter dados de fim de turno do CLP ID: "
					+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
					+ clp.getNome() + " Stack: " + e.getMessage());
			
		}
		try {
			if( comm != null ) {
				comm.disconnect();
				comm=null;
			}
		} catch(Exception e ) {
			logger.error(
					"Erro ao tentar obter dados de fim de turno do CLP ID: "
							+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
							+ clp.getNome(), e);
			registroErroSistemaService.criar(TipoErro.ERROS_EQUIPAMENTOS, "Erro ao tentar obter dados de fim de turno do CLP ID: "
					+ clp.getId() + " IP: " + clp.getIp() + " Nome: "
					+ clp.getNome() + " Stack: " + e.getMessage());
			
		}
		return retorno;
	}

	private Object obterDadosCLP(String variavel, int tamanhoArray,
			ControlLogixConnector comm) throws NotImplementedException,
			IOException, InterruptedException {
		int tentativas = 0;
		Object retorno = null;
		while (tentativas < 5) {
			UnconnectedMessagingRead messagingRead = new UnconnectedMessagingRead(
					variavel, tamanhoArray, comm.getSessionHandle());
			comm.executeMessage(messagingRead);
			retorno = messagingRead.getValues();
			messagingRead = null;
			if (retorno != null) {
				logger.info("Valor encontrado: " + retorno);
				break;
			}
			if (retorno == null) {
				Thread.sleep(10);
			}
			tentativas++;
		}
		return retorno;
	}
}
